package com.hqyj.shop.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hqyj.shop.mapper.UserInfoMapper;
import com.hqyj.shop.pojo.UserInfo;
import com.hqyj.shop.service.UserInfoService;
import com.hqyj.shop.util.JwtUtil;
import com.hqyj.shop.util.ResultVo;
import com.hqyj.shop.util.SHA3Util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 项目:shop-admin-240701
 * 描述:
 * 时间:2024/10/8 10:38
 * 作者:admin
 * 版本:1.0
 **/
@Service
@Slf4j
public class UserInfoServiceImpl implements UserInfoService {

    //注入userserMapper
    @Resource
    UserInfoMapper mapper;
    //注入邮件发送服务接口
    @Autowired
    JavaMailSender javaMailSender;
    //注入redis工具类
    @Autowired
    RedisTemplate<String,Object> redisTemplate;

    //读取配置文件里的邮箱
    @Value("${spring.mail.username}")
    private String mail;
    //读取密码输入错误上限
    @Value("${passwordError}")
    private int num;

    //业务：1 :发送验证码  2 ：邮箱验证 3 验证邮箱唯一性 4 存储验证码，设置验证码失效时间
    @Override
    public ResultVo getCode(UserInfo userInfo) {
        // 1验证邮箱唯一性
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email",userInfo.getEmail());
        UserInfo u =mapper.selectOne(queryWrapper);
        if(u!=null){
            log.info("邮箱已经被注册了");
           return ResultVo.error("邮箱已经被注册了");
        }
        try {
            // 2 发送验证码
            //创建一个邮件对象
            SimpleMailMessage message = new SimpleMailMessage();
            //收件人
            message.setTo(userInfo.getEmail());
            //发件人
            message.setFrom(mail);
            //标题
            message.setSubject("xxx网站用户邮箱注册");
            //正文
            Random rd = new Random();
            int code = rd.nextInt(10000);
            message.setText("你在xxx网站注册的验证码是:"+code);

            //发送邮件
            javaMailSender.send(message);
            log.info("邮件发送成功");
            //把验证码存入redis缓存里,并设置缓存失效时间是1分钟
            String key = "register:"+userInfo.getEmail();
            redisTemplate.opsForValue().set(key,code,60, TimeUnit.SECONDS);

        }catch (Exception e){
            e.printStackTrace();
            log.info("邮件发送失败");
        }
        return ResultVo.success();
    }
    //邮箱注册业务： 1 用户新增，2 数据加密，3 验证码校验
    @Override
    public ResultVo registerByEmail(UserInfo userInfo) {
        // 验证码校验
        String key = "register:"+userInfo.getEmail();
        Object obj = redisTemplate.opsForValue().get(key);
        if(obj==null){
            log.info("验证码失效");
            return ResultVo.error("验证码失效");
        }else if(!userInfo.getCode().equals(obj+"")){
            log.info("验证码不正确");
            return ResultVo.error("验证码不正确，请重新输入");
        }else{
            //密码加密
            String salt = SHA3Util.generateRandomSalt(16);
            String pwd = SHA3Util.hashWithSalt(userInfo.getPassword(),salt);
            //把盐值和密码存入到参数
            userInfo.setUserName(userInfo.getEmail());
            userInfo.setSalt(salt);
            userInfo.setPassword(pwd);
            int num = mapper.insert(userInfo);
            if(num > 0){
                return ResultVo.success();
            }
        }
        return ResultVo.error();
    }

    //业务： 1 用户名是否正确 2 密码是否正确(加密验证) 3 生成JWT
    @Override
    public ResultVo login(UserInfo userInfo) {
        //记录密码错误次数的key
        String key = "error:"+userInfo.getUserName();
        //记录锁定账号的key
        String keyLock = "lock:"+userInfo.getUserName();
        //获取锁定账号的值
        Object oj = redisTemplate.opsForValue().get(keyLock);
        if(oj!=null){
            log.info("账号被锁定");
            //清除密码输入错误次数
            redisTemplate.delete(key);
            return ResultVo.error("账号被锁定");
        }
        log.info("账号没被锁定");
        //验证用户名是否正确
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name",userInfo.getUserName());
        UserInfo u =  mapper.selectOne(queryWrapper);
        if(u==null){
            return ResultVo.error("用户名不正确");
        }
        // 密码校验
        String salt = u.getSalt();
        //加密
        String pwd = SHA3Util.hashWithSalt(userInfo.getPassword(),salt);
        if(pwd.equals(u.getPassword())){
            //清除密码输入错误次数
            redisTemplate.delete(key);
            //验证通过，生成JWT
            String jwtSalt = UUID.randomUUID()+"";
            String token =JwtUtil.createUserToken(u.getUserId()+"",u.getUserName(),jwtSalt);
            //用户id和token
            Map<String,Object> map = new HashMap<>();
            map.put("userId",u.getUserId());
            map.put("token",token);
            return ResultVo.success("success",map);
        }
        // 异常登录的监控业务

        //记录错误次数,i++;
        redisTemplate.opsForValue().increment(key,1);
        Object obj = redisTemplate.opsForValue().get(key);
        //判断是否有密码输入错误次数
        if(obj!=null){
            int o = Integer.parseInt(obj+"");
            if(o < num){
                log.info("你还有"+(num-o)+"次输入机会");
                return ResultVo.error("你还有"+(num-o)+"次输入机会");
            }else{
                redisTemplate.opsForValue().set(keyLock,1,1,TimeUnit.MINUTES);
                log.info("你的账号被锁定，请1分钟后再登录");
                //发送邮件业务
                return ResultVo.error("你的账号被锁定，请1分钟后再登录");
            }
        }

        return ResultVo.error("密码不正确");
    }
}
